February 09, 2021
μλ°μ€ν¬λ¦½νΈλ‘ ꡬν νλ μλμ°¨ κ²½μ£Ό κ²μ
λ―Έμ μ μ²μ μμνλ©΄μ νμ΄μΈ ν루μ ν¨κ» μλ‘μ΄ λ°©μμ λν μκΈ°λ₯Ό λλ΄μ΅λλ€. μ§λ μ΄κ°λ¨ λ―Έμ , κ³μ°κΈ° λ―Έμ μ μ§νν λλ λͺ¨λ ν μ€νΈλ₯Ό μμ±νκ³ κΈ°λ₯μ ꡬννλ λ°©μμΌλ‘ μ§ννμ΅λλ€. μ§λ κ°μμμ μ€μ΄ ν μ€νΈμ κΈ°λ₯μ λ²κ°μ μμ±νλ κ²μ λ³΄κ³ κ·Έ λ°©μμ λ°λΌν΄λ³΄κΈ°λ‘ νμ΅λλ€.
κ·Έλ¬λ μμ κ°μ λ°©μμΌλ‘ μ§ννλ μ€ μμνμ§ λͺ» νλ λ¬Έμ μ λ΄μ°©νμ΅λλ€. νλμ ν μ€νΈμ½λλ₯Ό μμ±νκ³ ν΄λΉ ν μ€νΈμ λν κΈ°λ₯μ ꡬννλ μ€ νλμ κΈ°λ₯ λ²μλ₯Ό μ΄κ³Όνλ κΈ°λ₯λ€μ λ§λ€κ² λλ λ¬Έμ μμ΅λλ€. λ¨Όμ κΈ°λ₯μ ꡬννκ³ ν΄λΉ κΈ°λ₯μ λν ν μ€νΈλ₯Ό μμ±νκ² λλ©΄ κΈ°λ₯μ λΌμλ§μΆλ― ν μ€νΈλ₯Ό μμ±νκ² λκ³ μ΄λ κ² λλ©΄ TDDλ₯Ό νλ μλ―Έκ° μλ€λ μκ°μ΄ λ€μμ΅λλ€. κ·Έλμ λ€μ μ΄μ μ²λΌ λͺ¨λ ν μ€νΈ μ½λλ₯Ό μμ±νκ³ κΈ°λ₯ ꡬνμ νλ λ°©μμΌλ‘ μ΄λ² λ―Έμ μ μ§ννμ΅λλ€.
ν루μ νμ΄ νλ‘κ·Έλλ°μ μ§ννλ©° ν μ€νΈ μ½λλ₯Ό μμ±νλ μ€ κ°μ₯ λ§μ μκΈ°λ₯Ό λλ λΆλΆμ μλμ°¨ κ²½μ£Όλ₯Ό μ§ννμ λ λλ€ν κ°μ λΆμ¬νκ³ κ·Έ κ²°κ³Όλ₯Ό ν μ€νΈ νλ λΆλΆμ΄μμ΅λλ€.
μ λ μ΄ λΆλΆμ ν΅ν©ν μ€νΈλ‘ μ§ννκ³ μΆμκ³ ν루λ μ΄ λΆλΆμ νλμ© λΆλ¦¬ν΄μ ν μ€νΈ νκΈ°λ₯Ό μνμ΅λλ€. μ΄ λΆλΆμ λν΄ λ§μ μκΈ°λ₯Ό λλ΄μ§λ§ κ²°λ‘ μ μΌλ‘λ μλμ κ°μ μ΄μ λ€λ‘ νμ΄μ μ견μ λ°λ₯΄κΈ°λ‘ κ²°μ νμ΅λλ€.
ν΅ν©ν μ€νΈ ꡬνμ λλ λΉμ©μ΄ λ¨μν μ€νΈλ₯Ό μ¬λ¬κ° μμ±νλ λΉμ©λ³΄λ€ ν¬λ€.
ν΅ν©ν μ€νΈμ μ¬λ¬ κ°μ λ¨μ ν μ€νΈλ₯Ό λΉκ΅νμ λ ν μ€νΈμ μ λ’°μ±μ ν° μ°¨μ΄κ° μλ€.
μμ κ°μ μ΄μ λ€λ‘ λλ€ν κ°μ λΆμ¬νκ³ κ·Έ κ²°κ³Όλ₯Ό ν μ€νΈνλ κΈ°λ₯μ ν΅ν© ν μ€νΈκ° μλ μ¬λ¬ κ°μ λ¨μ ν μ€νΈλ‘ μͺΌκ°μ ꡬννλ©° λΉ λ₯΄κ² μμ±μ λ§μΉ μ μμμ΅λλ€. BDD, TDD νλμ λ무 맀λͺ°λμ§ μκ³ μν©μ λ°λΌ μ μ νκ² μ νν μ μλλ‘ μκ°μ νμ λνκ³ μλμ κΈΈλ¬μΌκ² λ€λ μκ°μ νμ΅λλ€.
κΈ°λ₯ ꡬνμ νλ©΄μ ν μ€νΈλ₯Ό ν΅ν΄ κΈ°λ₯μ κ²μ¦νλ μ€ λ¬Έμ λ₯Ό λ°κ²¬νμ΅λλ€.
it('μλμ°¨ κ²½μ£Όλ₯Ό λ§μ³€μ λ μ°μΉμλ₯Ό μ μμ μΌλ‘ μΆλ ₯νλμ§ ν
μ€νΈ νλ€.', () => {
let winner
typeCarNameAndSubmit()
typeRacingCountAndSubmit()
winner = getWinner()
cy.get('#game-result-text').should(`π μ΅μ’
μ°μΉμ: ${winner} π`)
})
κΈ°λ₯ ꡬνμ μ¬μ©ν getWinner()
ν¨μλ₯Ό ν
μ€νΈ μ½λμμλ μ¬μ©ν΄ κ°λ¨νκ² ν
μ€νΈλ₯Ό ν κ³νμΌλ‘ μμ κ°μ ν
μ€νΈ μ½λλ₯Ό μμ±νμ΅λλ€. κ·Έλ¬λ μ μ½λμμλ typeCarNameAndSubmit()
, typeRacingCountAndSubmit()
ν¨μκ° μ€νλκΈ° μ getWinner()
κ° μ€νλλ μμ μμ μλμ°¨ λͺ©λ‘κ³Ό κ²μ μ§ν μν©μ λΆλ¬μ€μ§ λͺ» νμ΅λλ€.
it('λλ€ ν¨μκ° μ μμ μΌλ‘ λμνλμ§ ν
μ€νΈ νλ€.', () => {
const possibleScores = Array.from({
length: GAME.MAX_SCORE - GAME.MIN_SCORE + 1,
}).map((v, i) => i)
for (let i = 0; i < 100; i++) {
expect(possibleScores).to.include(getRandomNumber())
}
})
λΉμ·νκ² getRandomNumber()
ν¨μλ₯Ό νΈμΆν΄μ ν
μ€νΈνλ μ μ½λμ getRandomNumber()
κ°μ κ²½μ°λ μμ‘΄μ± μμ΄ λ
립μ μΌλ‘ μ€νλλ λͺ¨λμ΄μ§λ§ getWinner()
μ κ²½μ° μ€νλκΈ° μν΄μλ DOMμ μλ μμλ€μ΄ νμνκΈ° λλ¬Έμ μκΈ°λ λ¬Έμ μμ΅λλ€. async/await λ₯Ό μΆκ°ν΄λ³΄κΈ°λ νλ λ± μ¬λ¬ λ°©λ²μ μλνμ§λ§ ν
μ€νΈλ κ³μ μ€ν¨νμ΅λλ€. κ²°κ΅ setTimeOut()
μ ν΅ν΄ μμλ°©νΈμΌλ‘ μλμ κ°μ΄ ν
μ€νΈλ₯Ό κ³ μ³€μ΅λλ€.
it('μλμ°¨ κ²½μ£Όλ₯Ό λ§μ³€μ λ μ°μΉμλ₯Ό μ μμ μΌλ‘ μΆλ ₯νλμ§ ν
μ€νΈ νλ€.', () => {
let winner
typeCarNameAndSubmit()
typeRacingCountAndSubmit()
setTimeout(() => {
winner = getWinner()
cy.get('#game-result-text').should(`π μ΅μ’
μ°μΉμ: ${winner} π`)
}, 1000)
})
μμ κ°μ΄ ν
μ€νΈλ₯Ό κ³ μΉ ν β
λ₯Ό 보며 μΌλ¨μ μ€νλλ μνκΉμ§λ λ§λ€μλ€κ³ μκ°νμ§λ§ ν° μ°©κ°μ΄μμ΅λλ€. ν
μ€νΈκ° μ μμ μΌλ‘ μ€νλλ©° β
κ° μκΈ΄κ² μλκ³ setTimeOut()
κ° λμνμ§ μκ³ λμ΄κ°λ©΄μ β
κ° μμ±λκ³ μμμ΅λλ€. κ²°κ΅ λͺ¨λμ λΆλ¬μμ μ¬μ©νλ κ±Έ ν¬κΈ°νκ³ ν
μ€νΈ μ½λμμ μ§μ DOMμ νμ±ν΄μ μ€νλλλ‘ μλμ κ°μ΄ μ½λλ₯Ό μμ νμ΅λλ€.
it('μλμ°¨ κ²½μ£Όλ₯Ό λ§μ³€μ λ μ°μΉμλ₯Ό μ μμ μΌλ‘ μΆλ ₯νλμ§ ν
μ€νΈ νλ€.', () => {
typeCarNameAndSubmit()
typeRacingCountAndSubmit()
cy.get('.car').then($cars => {
const counts = [...$cars].map($car => {
return $car.querySelectorAll('.forward-icon').length
})
const maxScore = Math.max(...counts)
const winners = []
counts.forEach((carCount, index) => {
if (carCount === maxScore) {
winners.push(carNames[index])
}
})
cy.get('#game-result-text').should(
'have.text',
`π μ΅μ’
μ°μΉμ: ${winners.join(', ')} π`
)
})
})
μμ κ°μ΄ μ½λλ₯Ό μμ νκ³ λ€μ ν μ€νΈλ₯Ό ν΅ν΄ νμΈν΄λ³΄λ μ΄μ μμΌ μλλλ‘ ν μ€νΈκ° λμνλκ±Έ νμΈν μ μμμ΅λλ€.
μμ§ cypressμ μ΅μνμ§ μμ κ·Έλ°κ²λ μκ² μ§λ§ ν μ€νΈ μ½λ ꡬνκ³Ό κΈ°λ₯ ꡬνμ λκ³ λ΄€μ λ ν μ€νΈ μ½λλ₯Ό ꡬννλλ° λ μ€λ μκ°μ΄ 걸리λκ±° κ°μ΅λλ€. λ¬Όλ‘ ν μ€νΈ μ½λλ₯Ό 미리 ꡬνν¨μΌλ‘μ¨ κΈ°λ₯μ ꡬνν λ λΉ λ₯΄κ² μμ± κ°λ₯ν λΆλΆλ μλ€. νμ§λ§ κ²°κ΅ ν μ€νΈ μ½λκ° λͺ¨λ μμΈμ¬νμ 100% 컀λ²ν μλ μκΈ° λλ¬Έμ μ΄λ μ λ μμ€κΉμ§ 컀λ²ν μ μκ² ν μ€νΈ μ½λλ₯Ό μμ±ν΄μΌ ν μ§μ λν κ³ λ―Όμ νκ³ μμ΅λλ€.
μ΄μ λ§ cypressλ₯Ό μ²μ μ¬μ©ν΄λ³΄λ©΄μ ν μ€νΈ μ½λλ₯Ό μ²μ μμ±νκΈ° λλ¬Έμ μκΈ°λ κ³ λ―ΌμΈκ±° κ°κΈ°λ ν©λλ€. μ§μμ μΌλ‘ ν μ€νΈλ₯Ό μμ±νλ©΄μ μλ ¨λκ° μ€λ₯Έλ€λ©΄ μ΄λ° κ³ λ―Όμ νμ§ μμλ λ κ±° κ°λ€λ μκ°μ νμ΅λλ€.
debouncing
, throttling
μ ν΅ν΄ μ΄λ²€νΈλ₯Ό μ μ΄ν μ μλ€λκ±Έ λ¦¬λ·°μ΄ λΆμ΄ λ¨κ²¨μ£Όμ 리뷰λ₯Ό ν΅ν΄ μ²μμΌλ‘ μκ² λμ΅λλ€. μ§κΈμ λ¨μν <button>
μ ν΄λ¦μ΄ νλ² λ°μνλ©΄ ν΄λΉ λ
Έλμ disabled
μμ±μ λΆμ¬ν΄ μ΄λ²€νΈκ° λ€μ νΈμΆλλκ±Έ λ§κ³ μλλ° ν΄λΉ μ½λλ₯Ό λ³΄κ³ μ΄λ° κΈ°λ²λ€μ λν΄ μκ°ν΄μ£Όμ
¨μ΅λλ€.
debouncing
: λ§μ§λ§ ν¨μκ° νΈμΆλ ν μΌμ μκ° λμ ν¨μμ νΈμΆμ λ§λ κ².
throttling
:
μ΄ ν€μλλ₯Ό μ κΈ°μ΅ν΄λλ€κ° μ΄λ²€νΈκ° λ¨ μκ°μ μ¬λ¬λ² νΈμΆ λλ κ²μ λ°©μ§ν΄μΌν μν©μμ μ¬μ©ν΄λ΄μΌκ² λ€κ³ μκ° νμ΅λλ€.
cypressμμ μμ±ν ν¨μμ λ€μ΄λ°μ λν νΌλλ°±μ λ°μμ΅λλ€. cypressμ type
κ³Ό click
λ©μλλ₯Ό μ€νν΄μ£Όλ ν¨μμΈ λ§νΌ νΌλλ°±λλ‘ λ¨μν type...AndSubmit
보λ€λ click
μ΄λΌλ μ΄λ¦μ΄ λ€μ΄κ°λκ² μ§κ΄μ μΌκ±°λΌλ μκ°μ νμ΅λλ€.
νΌλλ°±μ ν΅ν΄ ν¨μλ₯Ό μλμ κ°μ΄ λ³κ²½νμ΅λλ€.
// λ³κ²½ μ
const typeCarNameAndSubmit = (){...}
const typeRacingCountAndSubmit = () => {...};
// λ³κ²½ ν
const typeCarNameAndClickToSubmitButton = (){...}
const typeRacingCountAndClickToSubmitButton = () => {...};
μμΌλ‘ ν¨μλ λ³μμ λ€μ΄λ°μ λμ± μ κ²½μ μ¨μΌκ² λ€κ³ λκΌμ΅λλ€.
ν μ€νΈ μ½λλ₯Ό λͺ λͺ ν λλ μμμ±μ§ λͺ» νλλ° νΌλλ°±μ λ°μΌλ λ°λ‘ λ¬Έμ μ μ μ°Ύμ μ μμμ΅λλ€. λ¦¬λ·°μ΄ λΆμ νΌλλ°±λλ‘ κ³Όκ±°μ μ½λλ₯Ό νμ¬ ν μ€νΈ νλ κ²μ΄κΈ° λλ¬Έμ μ μν΄μ£Όμ λͺ λͺ λ²μ΄ κ°λ μ±κ³Ό λͺ νμ± λ λ€ λ°μ΄λλ€λ μκ°μ νμ΅λλ€.
μ΄ λΆλΆμ μ€μ μ½λκ° μλμ κ°μ΄ ꡬμ±λμ΄ μμμ΅λλ€.
it('μμμ 곡백μ μλ νμλ‘ μ
λ ₯ μ, κ²½κ³ λ©μΈμ§κ° μΆλ ₯λλμ§ ν
μ€νΈ νλ€.', () => {
const negativeRacingCount = -7
const alertStub = cy.stub()
cy.on('window:alert', alertStub)
typeCarNameAndClickToSubmitButton()
typeRacingCountAndClickToSubmitButton(negativeRacingCount).then(() => {
expect(alertStub.getCall(0)).to.be.calledWith(
'1 μ΄μμ μ«μλ₯Ό μ
λ ₯ν΄μ£ΌμΈμ.'
)
cy.get('#racing-count-input').should('have.text', '')
})
cy.get('#racing-count-submit')
.click()
.then(() => {
expect(alertStub.getCall(1)).to.be.calledWith(
'1 μ΄μμ μ«μλ₯Ό μ
λ ₯ν΄μ£ΌμΈμ.'
)
cy.get('#racing-count-input').should('have.text', '')
})
})
μ€μ λ‘λ nagative μΌμ΄μ€λ€μ ν
μ€νΈ νλ μ½λμλλ° 'μμ μ μλ§μ μλνμλ‘ μ
λ ₯ν μ μλμ§ ν
μ€νΈ νλ€.'
λΌλ κΈ°μ‘΄μ μ΄λ¦μ μ€μ μλνλ ν
μ€νΈμλ κ±°λ¦¬κ° μλ€κ³ λκΌμ΅λλ€.
νΌλλ°±μ ν λλ‘ ν μ€νΈλ€μ μ΄λ¦μ μμ νλλ° ν¨μ¬ μν μ΄ λͺ ννκ² λ³΄μ΄λκ² λκ»΄μ‘μ΅λλ€.
λ¦¬λ·°μ΄ λΆμ λ§λλ‘ λ²μ©μ±μ μκ°νλ©΄ default parameter
λ₯Ό μ¬μ©νμ§ μκ³ μΈμλ₯Ό μ λ¬ λ°λκ² ν¨μ¬ λμκ±°λΌλ μκ°μ νμ΅λλ€. utils
ν΄λμ μμ±ν κ²λ λ²μ©μ μΌλ‘ μ¬μ©νκΈ° μν¨μ΄μλλ° default parameter
λ₯Ό μ¬μ©ν¨μΌλ‘μ¨ μ νμ μΌλ‘ μ¬μ©λλ€λ μ μ μκ°νμ§ λͺ» νμ΅λλ€. νΌλλ°±μ λ°μν΄ default parameter
λ₯Ό μ κ±°νμ΅λλ€.